// Copyright (C) joyinter
// All rights reserved.
// 
// Author : Jiang Li
// Date   : 2005-1-13

#include "stdafx.h"
#include <common/svr_base/svr_showinfo.h>
#include <common/svr_base/svr_netmsg.h>
#include "trans_analyzer.h"
#include "trans_tcp.h"
#include "trans_tcpsocket.h"
#include "msvr_server.h"
#include "msvr_user.h"
#include "msvr_room.h"
#include <common/base/convertdef.h>

namespace JoyServer
{

class CJoyTransAcceptMsg : public CJoyUserSetMsg
{
protected:
    virtual void OnExecute();
public:
    CJoyTransTCPSocket* m_socket;

    CJoyTransAcceptMsg(CJoyTransTCPSocket* sock)
    {
        m_socket = sock;
    }
    virtual ~CJoyTransAcceptMsg()
    {
    }
};

void CJoyTransAcceptMsg::OnExecute()
{
    CJoyMainRoom* pRoom = (CJoyMainRoom*)GetUserSet();
    CJoyAutoCS gate(pRoom->m_userLock);
    
    CJoyTransTCP* transTCP = pRoom->m_transTCP;
    transTCP->m_sockets[m_socket] = NULL;

    m_socket->QueueRecv();

    // do timeout check.
    DWORD tick = GetTickCount();
    if(tick-transTCP->m_lastCheck < 60000)
    {
        return;
    }
    transTCP->m_lastCheck = tick;

    POSITION pos = transTCP->m_sockets.GetStartPosition();
    while(pos != NULL)
    {
        CJoyTransTCPSocket* pSock;
        CJoyMainUser* pUser;
        transTCP->m_sockets.GetNextAssoc(pos, pSock, pUser);
        if(pUser != NULL)
        {
            continue;
        }
        if(tick-pSock->m_acceptedTick > 60000)
        {
            transTCP->m_sockets.RemoveKey(pSock);
            pSock->Close();
            delete pSock;
        }
    }
}

// CJoyTransTCP

CJoyTransTCP::CJoyTransTCP()
{
    m_room      = NULL;
    m_lastCheck = 0;
}

CJoyTransTCP::~CJoyTransTCP()
{
}

bool CJoyTransTCP::Create(CJoyMainRoom* pRoom)
{
    m_room = pRoom;
    CJoyMainServer* pServer = m_room->GetServer();
    CJoyShowInfo* showInfo = pServer->m_showInfo;

    if(!__super::Create(true))
    {
        showInfo->QueueTimeColorText(InfoColor_Error,
            "cannot create TransTCP acceptor of room <%s>.\n", (PCSTR)pRoom->m_roomName);
        return false;
    }

    if(!__super::Bind(pServer->m_serverIP, pRoom->m_roomPort))
    {
        showInfo->QueueTimeColorText(InfoColor_Error,
            "cannot bind address<%s:%d>.\n", pServer->m_serverIP, pRoom->m_roomPort);
        return false;
    }

    if(!Start(4))
    {
        showInfo->QueueTimeColorText(InfoColor_Error,
            "start TransTCP acceptor failed of room <%s>.\n", (PCSTR)pRoom->m_roomName);
        return false;
    }

    m_lastCheck = GetTickCount();
    return true;
}

void CJoyTransTCP::Destroy()
{
    __super::Close();

    POSITION pos = m_sockets.GetStartPosition();
    while(pos != NULL)
    {
        CJoyTransTCPSocket* pSock;
        CJoyMainUser* pUser;
        m_sockets.GetNextAssoc(pos, pSock, pUser);
        if(pUser != NULL)
        {
            pUser->m_tcpSock = NULL;
        }
        pSock->Close();
        delete pSock;
    }
    m_sockets.RemoveAll();
}

void CJoyTransTCP::RemoveSocket(CJoyTransTCPSocket* pSocket)
{
    CJoyMainUser* pUser = NULL;
    if(!m_sockets.Lookup(pSocket, pUser))
    {
        return;
    }
    if(pUser != NULL)
    {
        pUser->m_tcpSock = NULL;
    }
    pSocket->Close();
    delete pSocket;
    m_sockets.RemoveKey(pSocket);
}

bool CJoyTransTCP::OnAccept(SOCKET s, const sockaddr_in& )
{
    CJoyTransTCPSocket* sock = new CJoyTransTCPSocket();
    sock->m_room    = m_room;
    if(!sock->Attach(s))
    {
        sock->Close();
        delete sock;
        return false;
    }

    CJoyTransAcceptMsg* pMsg = new CJoyTransAcceptMsg(sock);
    m_room->QueueMsg(pMsg);
	/*test lly----------------------------------------------*/
	int buflen;
	buflen=300*1024;
	int sizeo=sizeof(int);
	sizeo=setsockopt(s,SOL_SOCKET,SO_SNDBUF,(char *)&buflen,sizeo);
	sizeo=setsockopt(s,SOL_SOCKET,SO_RCVBUF,(char *)&buflen,sizeo);
	/*test lly----------------------------------------------*/
    
    return true;
}

// class CJoyMainUser

void CJoyMainUser::TransSendTCP(CJoyTransmitData* pData)
{
    if(m_tcpSock == NULL)
    {
        return;
    }
    m_tcpSock->Send(pData);
}

void CJoyMainUser::TransSendTCP(const JoyMessage::MessageBase* msg)
{
    CJoyTransmitData* pData = JoyMsgTool::BuildMsgData(msg);
    TransSendTCP(pData);
    pData->Release();
}

void CJoyMainUser::OnNetMsg_SockTransmitTCP(const JoyMessage::MC_SockTransmitTCP* msg)
{
    if(m_dummyIPSlot == NULL)
    {
        return;
    }
    CJoyMainUser* dstUser = m_room->FindUserByDummyIP(msg->m_dstIP);
    if(dstUser == NULL)
    {
        return;
    }

    CJoyTransContext ctx;
    ctx.m_srcUser   = this;
    ctx.m_dstUser   = dstUser;
    ctx.m_transType = Trans_TCP;
    ctx.m_inBuf     = (void*)msg->m_data;
    ctx.m_inLen     = msg->GetDataLength();

    m_room->m_transAnalyzer->OnTransmit(ctx);

//added by deng 050614
#ifndef USE_TCP_TO_UDP////lly 2006.9.15
    const void* outBuf;
    int outLen;
    if(ctx.m_outBuf.IsEmpty())
    {
        outBuf = ctx.m_inBuf;
        outLen = ctx.m_inLen;
    }
    else
    {
        outBuf = ctx.m_outBuf.GetBuffer();
        outLen = ctx.m_outBuf.GetSize();
    }

    CJoyBuffer msgBuf(sizeof(JoyMessage::MS_SockTransmitTCP)+outLen);
    JoyMessage::MS_SockTransmitTCP* sendMsg =
        (JoyMessage::MS_SockTransmitTCP*) msgBuf.GetBuffer();
    JoyConstruct(sendMsg);
    sendMsg->m_dstId    = msg->m_dstId;
    sendMsg->SetDataLength(outLen);
    memcpy(sendMsg->m_data, outBuf, outLen);

    dstUser->TransSendTCP(sendMsg);
#endif
}

void CJoyMainUser::OnNetMsg_SockAccept(const JoyMessage::MC_SockAccept* msg)
{
    if(m_dummyIPSlot == NULL)
    {
        return;
    }
    JoyMessage::MS_SockAccept acceptMsg;
    acceptMsg.m_srcId = msg->m_srcId;
    acceptMsg.m_dstId = msg->m_dstId;
    acceptMsg.m_accept= msg->m_accept;

    CJoyMainUser* pUser = m_room->FindUserByDummyIP(msg->m_dstIP);
    if(pUser != NULL)
    {
        pUser->TransSendTCP(&acceptMsg);
    }
    else
    {
        JoyMessage::MS_SockClose connMsg;
        connMsg.m_dstId = msg->m_srcId;
        TransSendTCP(&connMsg);
    }
}

void CJoyMainUser::OnNetMsg_SockConnect(const JoyMessage::MC_SockConnect* msg)
{
    if(m_dummyIPSlot == NULL)
    {
        return;
    }
    JoyMessage::MS_SockConnect connMsg;
    connMsg.m_dstPort   = msg->m_dstPort;
    connMsg.m_srcId     = msg->m_srcId;
    connMsg.m_srcIP     = m_dummyIPSlot->m_dummyIP;

    CJoyMainUser* pUser = m_room->FindUserByDummyIP(msg->m_dstIP);
    if(pUser != NULL)
    {
        pUser->TransSendTCP(&connMsg);
    }
    else
    {
        JoyMessage::MS_SockClose connMsg;
        connMsg.m_dstId = msg->m_srcId;
        TransSendTCP(&connMsg);
    }
}

void CJoyMainUser::OnNetMsg_SockClose(const JoyMessage::MC_SockClose* msg)
{
    if(m_dummyIPSlot == NULL)
    {
        return;
    }
    JoyMessage::MS_SockClose connMsg;
    connMsg.m_dstId = msg->m_dstId;

    CJoyMainUser* pUser = m_room->FindUserByDummyIP(msg->m_dstIP);
    if(pUser != NULL)
    {
        pUser->TransSendTCP(&connMsg);
    }
}

} // namespace JoyServer